package com.benjaminwan.read.free.ui.script

import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.args
import com.airbnb.mvrx.withState
import com.benjaminwan.read.free.R
import com.benjaminwan.read.free.base.adapter.simpleController
import com.benjaminwan.read.free.base.fragment.BaseFragment
import com.benjaminwan.read.free.base.viewmodel.state
import com.benjaminwan.read.free.config.GroupConfig.getGroupConfig
import com.benjaminwan.read.free.databinding.FragmentGroupBinding
import com.benjaminwan.read.free.model.action.Delay
import com.benjaminwan.read.free.model.action.Group
import com.benjaminwan.read.free.model.action.KeyboardClick
import com.benjaminwan.read.free.model.action.KeyboardKeyDown
import com.benjaminwan.read.free.model.action.KeyboardKeyUp
import com.benjaminwan.read.free.model.action.MouseButtonClick
import com.benjaminwan.read.free.model.action.MouseButtonDown
import com.benjaminwan.read.free.model.action.MouseButtonUp
import com.benjaminwan.read.free.model.action.MouseDragPage
import com.benjaminwan.read.free.model.action.MouseMove
import com.benjaminwan.read.free.model.action.MouseMoveLong
import com.benjaminwan.read.free.model.action.MouseScroll
import com.benjaminwan.read.free.model.action.Position
import com.benjaminwan.read.free.model.enums.Horizontal
import com.benjaminwan.read.free.model.enums.Vertical
import com.benjaminwan.read.free.ui.main.MainState
import com.benjaminwan.read.free.ui.main.MainViewModel
import com.benjaminwan.read.free.utils.actionRightMenu
import com.benjaminwan.read.free.utils.copySwap
import com.benjaminwan.read.free.utils.setMarginItemDecoration
import com.benjaminwan.read.free.utils.setTitle
import com.benjaminwan.read.free.views.actionItemView
import com.benjaminwan.read.free.views.superTextViewItemView

class GroupFragment : BaseFragment() {
    companion object {
        fun arg(index: Int): Bundle {
            val args = Bundle()
            args.putInt(MvRx.KEY_ARG, index)
            return args
        }
    }

    private val idGroup by args<Int>()
    private val mainVM by activityViewModel(MainViewModel::class)
    private val epoxyControllerSetting by lazy { epoxyControllerSetting() }
    private val epoxyController by lazy { epoxyController() }

    private fun getGroup(main: MainState): Group {
        return main.script.groups[idGroup]
    }

    private val defaultMemo: String
        get() = "组${idGroup + 1}"

    private lateinit var binding: FragmentGroupBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentGroupBinding.inflate(layoutInflater)
        return binding.root
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        epoxyControllerSetting.onRestoreInstanceState(savedInstanceState)
        epoxyController.onRestoreInstanceState(savedInstanceState)
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        epoxyControllerSetting.onSaveInstanceState(outState)
        epoxyController.onSaveInstanceState(outState)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setHasOptionsMenu(true)
        initViews()
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        menu.clear()
        inflater.inflate(R.menu.menu_group, menu)
    }

    override fun onPrepareOptionsMenu(menu: Menu) {
        super.onPrepareOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean =
        when (item.itemId) {
            R.id.menu_clear_group -> {
                mainVM.setGroup(
                    idGroup, Group(memo = defaultMemo)
                )
                true
            }

            R.id.menu_add_delay -> {
                mainVM.addActionToGroup(idGroup, Delay())
                true
            }

            R.id.menu_add_keyboard_key_down -> {
                mainVM.addActionToGroup(idGroup, KeyboardKeyDown())
                true
            }

            R.id.menu_add_keyboard_key_up -> {
                mainVM.addActionToGroup(idGroup, KeyboardKeyUp())
                true
            }

            R.id.menu_add_mouse_button_down -> {
                mainVM.addActionToGroup(idGroup, MouseButtonDown())
                true
            }

            R.id.menu_add_mouse_button_up -> {
                mainVM.addActionToGroup(idGroup, MouseButtonUp())
                true
            }

            R.id.menu_add_mouse_scroll -> {
                mainVM.addActionToGroup(idGroup, MouseScroll())
                true
            }

            R.id.menu_add_mouse_move -> {
                mainVM.addActionToGroup(idGroup, MouseMove())
                true
            }

            R.id.menu_add_keyboard_click -> {
                mainVM.addActionToGroup(idGroup, KeyboardClick())
                true
            }

            R.id.menu_add_mouse_button_click -> {
                mainVM.addActionToGroup(idGroup, MouseButtonClick())
                true
            }

            R.id.menu_add_mouse_move_long -> {
                mainVM.addActionToGroup(idGroup, MouseMoveLong())
                true
            }

            R.id.menu_add_mouse_move_left_top -> {
                val globalConfig = mainVM.state.script.globalConfig
                val screenX = globalConfig.screenX
                val screenY = globalConfig.screenY
                val stepXRange = ((screenX / 100)..(screenX / 100))
                val stepYRange = ((screenY / 100)..(screenY / 100))
                mainVM.addActionToGroup(
                    idGroup,
                    MouseMoveLong(-screenX, -screenY, stepXRange, stepYRange)
                )
                true
            }

            R.id.menu_add_mouse_move_right_top -> {
                val globalConfig = mainVM.state.script.globalConfig
                val screenX = globalConfig.screenX
                val screenY = globalConfig.screenY
                val stepXRange = ((screenX / 100)..(screenX / 100))
                val stepYRange = ((screenY / 100)..(screenY / 100))
                mainVM.addActionToGroup(
                    idGroup,
                    MouseMoveLong(screenX, -screenY, stepXRange, stepYRange)
                )
                true
            }

            R.id.menu_add_mouse_move_left_bottom -> {
                val globalConfig = mainVM.state.script.globalConfig
                val screenX = globalConfig.screenX
                val screenY = globalConfig.screenY
                val stepXRange = ((screenX / 100)..(screenX / 100))
                val stepYRange = ((screenY / 100)..(screenY / 100))
                mainVM.addActionToGroup(
                    idGroup,
                    MouseMoveLong(-screenX, screenY, stepXRange, stepYRange)
                )
                true
            }

            R.id.menu_add_mouse_move_right_bottom -> {
                val globalConfig = mainVM.state.script.globalConfig
                val screenX = globalConfig.screenX
                val screenY = globalConfig.screenY
                val stepXRange = ((screenX / 100)..(screenX / 100))
                val stepYRange = ((screenY / 100)..(screenY / 100))
                mainVM.addActionToGroup(
                    idGroup,
                    MouseMoveLong(screenX, screenY, stepXRange, stepYRange)
                )
                true
            }

            R.id.menu_add_mouse_drag_x -> {
                mainVM.addActionToGroup(
                    idGroup,
                    MouseDragPage(
                        xDirection = Horizontal.LEFT,
                        yDirection = Vertical.UP,
                        dxRange = (150..150),
                        dyRange = (0..0),
                        stepXRange = (5..7),
                        stepYRange = (1..1)
                    )
                )
                true
            }

            R.id.menu_add_mouse_drag_y -> {
                mainVM.addActionToGroup(
                    idGroup,
                    MouseDragPage(
                        xDirection = Horizontal.LEFT,
                        yDirection = Vertical.UP,
                        dxRange = (0..0),
                        dyRange = (200..200),
                        stepXRange = (1..1),
                        stepYRange = (5..7)
                    )
                )
                true
            }

            else -> {
                super.onOptionsItemSelected(item)
            }
        }

    private fun initViews() {
        binding.groupSettingRv.setHasFixedSize(false)
        binding.groupSettingRv.setMarginItemDecoration(2, 1, 2, 1)
        binding.groupSettingRv.setController(epoxyControllerSetting)
        binding.actionGroupRv.setHasFixedSize(true)
        binding.actionGroupRv.setMarginItemDecoration(2, 1, 2, 1)
        binding.actionGroupRv.setController(epoxyController)
    }

    override fun invalidate() = withState(mainVM) { main ->
        requireActivity().invalidateOptionsMenu()
        binding.actionGroupRv.requestModelBuild()
        binding.groupSettingRv.requestModelBuild()
        val group = getGroup(main)
        setTitle("Group${idGroup + 1}(${group.memo})")
        Unit
    }

    private fun epoxyControllerSetting() = simpleController(mainVM) { main ->
        val configList = getGroupConfig(mainVM, idGroup)
        for ((index, group) in configList.withIndex()) {
            superTextViewItemView {
                id("GroupSettings:$index${group.hashCode()}")
                enable(true)
                itemType(group.type)
                leftText(group.leftText)
                rightText(group.rightText)
                isChecked(group.isChecked)
                visibility(group.visibility)
                onClickListener { view ->
                    group.click(view)
                }
                onCheckedChangeListener { buttonView, isChecked ->
                    group.checkedChange(buttonView, isChecked)
                }
            }
        }
    }

    private fun epoxyController() = simpleController(mainVM) { main ->
        val group = getGroup(main)
        group.actions.forEachIndexed { idAction, action ->
            actionItemView {
                id("GroupEditAction:${idGroup}:${idAction}}${group.hashCode()}${action.hashCode()}")
                actionIndex("${idAction + 1}")
                actionType(action.actionType.name)
                actionParam(action.toString())
                backgroundRes(R.drawable.bg_blue5_to_blue7)
                marginLeft(1)
                onClickListener { view ->
                    findNavController().navigate(
                        R.id.action_groupFragment_to_actionFragment,
                        ActionFragment.arg(
                            Position(idGroup, idAction)
                        )
                    )
                }
                rightMenu(
                    actionRightMenu.filterNot {
                        (idAction == 0 && it.id == 1) || (idAction == (group.actions.size - 1) && it.id == 2)
                    }
                )
                onRightMenuClickListener { swipeMenuLayout, item ->
                    when (item.id) {
                        0 -> mainVM.setAction(
                            Position(idGroup, idAction), null
                        )

                        1 -> {
                            val actions = group.actions.copySwap(idAction, idAction - 1)
                            mainVM.setGroup(idGroup, group.copy(actions = actions))
                        }

                        2 -> {
                            val actions = group.actions.copySwap(idAction, idAction + 1)
                            mainVM.setGroup(idGroup, group.copy(actions = actions))
                        }
                    }
                    swipeMenuLayout.closeMenu()
                }
            }
        }
    }

}